﻿SmitearWebGL.Core.Render.RenderEntry = Class.extend(
{
	/******** constructor ********/

	init : function()
	{
		this._registClass( "SmitearWebGL.Core.Render.RenderEntry" );
		
		this.detailLevel = 0;		//4 bits
		this.modelType = 0;			//2 bits
		this.boneCount = 0;			//2 bits
		this.renderPass = 0;		//8 bits
		this.hProgram = 0;			//16 bits
		
		this.modelParamA = 0;		//16 bits
		this.primaryParam = 0;		//16 bits
		
		this.hSurfaceMaterial = 0;	//16 bits
		this.modelParamB = 0;		//16 bits
		
		this.renderObject = null;
		this.userData = null;
	}
	,
	getSortValueA : function()
	{
		var result = ( this.detailLevel << SmitearWebGL.Core.Render.RenderEntry.eBitOffset.k_detailLevel ) |
					( this.modelType << SmitearWebGL.Core.Render.RenderEntry.eBitOffset.k_modelType ) |
					( this.boneCount << SmitearWebGL.Core.Render.RenderEntry.eBitOffset.k_boneCount ) |
					( this.renderPass << SmitearWebGL.Core.Render.RenderEntry.eBitOffset.k_renderPass ) |
					( this.hProgram << SmitearWebGL.Core.Render.RenderEntry.eBitOffset.k_hShader );
		
		return result >>> 0;
	}
	,
	getSortValueB : function()
	{
		var result = ( this.modelParamA << SmitearWebGL.Core.Render.RenderEntry.eBitOffset.k_modelParamA ) |
					( this.primaryParam << SmitearWebGL.Core.Render.RenderEntry.eBitOffset.k_primaryParam );
		
		return result >>> 0;
	}
	,
	getSortValueC : function()
	{
		var result = ( this.hSurfaceMaterial << SmitearWebGL.Core.Render.RenderEntry.eBitOffset.k_hSurfaceMaterial ) |
					( this.modelParamB << SmitearWebGL.Core.Render.RenderEntry.eBitOffset.k_modelParamB );
		
		return result >>> 0;
	}
	,
	clear : function()
	{
		this.detailLevel = 0;		//4 bits
		this.modelType = 0;			//2 bits
		this.boneCount = 0;			//2 bits
		this.renderPass = 0;		//8 bits
		this.hProgram = 0;			//16 bits
		
		this.modelParamA = 0;		//16 bits
		this.primaryParam = 0;		//16 bits
		
		this.hSurfaceMaterial = 0;	//16 bits
		this.modelParamB = 0;		//16 bits
		
		this.renderObject = null;
		this.userData = null;
	}
}
);

SmitearWebGL.Core.Render.RenderEntry.eTypeFlags =
{
	k_bufferEntry :	0,
	k_modelEntry :	1
}

SmitearWebGL.Core.Render.RenderEntry.eBitOffset =
{
	k_detailLevel :			0,
	k_modelType :			4,
	k_boneCount :			6,
	k_renderPass :			8,
	k_hShader :				16,
	
	k_modelParamA :			0,
	k_primaryParam :		16,
	
	k_hSurfaceMaterial :	0,
	k_modelParamB :			16
}

SmitearWebGL.Core.Render.RenderQueue = Class.extend(
{
	/******** constructor ********/

	init : function()
	{
		this._registClass( "SmitearWebGL.Core.Render.RenderQueue" );
		
		this._activeEntries = 0;
		this._entryList = new Array( SmitearWebGL.Core.Render.RenderQueue.k_maxRenderEntries );
		
		for ( var i = 0; i < SmitearWebGL.Core.Render.RenderQueue.k_maxRenderEntries; ++ i )
		{
			this._entryList[i] = new SmitearWebGL.Core.Render.RenderEntry();
		}
	}
	,
	lockRenderEntry : function()
	{
		if ( this._activeEntries + 1 == SmitearWebGL.Core.Render.RenderQueue.k_maxRenderEntries )
		{
			this.execute();
		}
	
		var pEntry = this._entryList[this._activeEntries];
	
		pEntry.clear();
	
		return pEntry;
	}
	,
	unlockRenderEntry : function( pEntry )
	{
		this._entryList[this._activeEntries] = pEntry;
		
		++ this._activeEntries;
	}
	,
	execute : function()
	{
		if ( this._activeEntries )
		{
			var hr = SmitearWebGL.Core.HResult.SUCCESS;
			
			// sort the entry list
			var entryList = this.sortEntryList();
	
			// issue the callback to render
			// the first item in the queue with all
			// activation flags set
			var activationFlags = new SmitearWebGL.Core.Math.BitFlags( 0xffffffff );
			hr |= entryList[0].renderObject.renderCallBack( entryList[0], activationFlags );
	
			// render any additional items,
			// sending only the flags for resources
			// which must be activated
			for ( var i = 1; i < this._activeEntries; ++ i )
			{
				var currentEntry = entryList[i];
				var previousEntry = entryList[i-1];
	
				activationFlags.clear();
	
				//
				// check for effect changes
				//
				if ( previousEntry.hProgram != currentEntry.hProgram )
				{
					// end the last render method
//					var pLastMethod = g_shaderManager.getResourceByHandle( previousEntry.hProgram );
//					if ( pLastMethod )
//					{
//						pLastMethod.release();
//					}
					
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateRenderMethod );
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateSurfaceMaterial );
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateRenderMethodParam );
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateModelParamA );
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateModelParamB );
				}
				else if ( previousEntry.renderPass != currentEntry.renderPass )
				{
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateRenderMethodPass );
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateRenderMethodParam );
				}		
				else 
				{
					if ( previousEntry.boneCount != currentEntry.boneCount )
					{
						activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateRenderMethodParam );
					}		
					if ( previousEntry.detailLevel != currentEntry.detailLevel )
					{
						activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateRenderMethodLOD );
					}		
				}
				
				//
				// check for model changes
				//
				if ( previousEntry.primaryParam != currentEntry.primaryParam ||
					previousEntry.modelType != currentEntry.modelType )
				{
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateModel );
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateModelParamA );
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateModelParamB );
				}
				else 
				{
					if ( previousEntry.modelParamA != currentEntry.modelParamA )
					{
						activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateModelParamA );
					}		
					if ( previousEntry.modelParamB != currentEntry.modelParamB )
					{
						activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateModelParamB );
					}		
				}
				
				//
				// Check for surface material changes
				//
				if ( previousEntry.hSurfaceMaterial != currentEntry.hSurfaceMaterial )
				{
					activationFlags.setBit( SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits.k_activateSurfaceMaterial );
				}		
	
				//
				// issue the callback to render
				//
				hr |= currentEntry.renderObject.renderCallBack( currentEntry, activationFlags );
			}
	
			// end the last render method
//			var lastEntry = entryList[this._activeEntries-1];
//			var pLastMethod = g_shaderManager.getResourceByHandle( lastEntry.hProgram );
//	
//			if (pLastMethod)
//			{
//				pLastMethod.release();
//			}
		}
	
		// reset for the next frame
		this.reset();
		
		this.debugRenderStatus( hr );
		
		return hr;
	}
	,
	sort_less : function( a, b )
	{
		var vaa = a.getSortValueA();
		var vba = b.getSortValueA();
		var vab = a.getSortValueB();
		var vbb = b.getSortValueB();
		var vac = a.getSortValueC();
		var vbc = b.getSortValueC();
		
		if (vaa > vba)
		{
			return false;
		}
		else if (vaa < vba)
		{
			return true;
		}

		if (vab > vbb)
		{
			return false;
		}
		else if (vab < vbb)
		{
			return true;
		}

		if (vac > vbc)
		{
			return false;
		}
		else if (vac < vbc)
		{
			return true;
		}

		return false;
	}
	,
	sortEntryList : function()
	{
		var el = this._entryList.slice( 0, this._activeEntries );
		el.sort( this.sort_less );
		
		return el;
//		SmitearWebGL.Utils.QuickSort( this._entryList, this._activeEntries, sort_less );
	}
	,
	reset : function()
	{
		this._activeEntries = 0;
	}
	,
	debugRenderStatus : function( hResult )
	{
		if ( hResult > 0 )
		{
			$WARNING( "警告:出现渲染状态异常,代码:" + hResult );
		}
	}
}
);

SmitearWebGL.Core.Render.RenderQueue.k_maxRenderEntries = 1024;

SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits =
{
	k_activateRenderMethod : 		0,
	k_activateRenderMethodPass :	1,
	k_activateRenderMethodParam :	2,
	k_activateRenderMethodLOD :		3,
	k_activateModel :				4,
	k_activateModelParamA :			5,
	k_activateModelParamB :			6,
	k_activateSurfaceMaterial :		7,

	k_totalActivationFlags :		8
};